﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Threading;
using AgilePlannerDT.Application;
using AgilePlannerDT.Application.Commands;
using AgilePlannerDT.Application.Commands.Impl;
using AgilePlannerDT.Application.Modules;
using AgilePlannerDT.Application.Modules.Impl;
using AgilePlannerDT.Data;
using AgilePlannerDT.Display;
using AgilePlannerDT.Display.Impl;
using AgilePlannerDT.Persister;
using AgilePlannerDT.Persister.Impl;
using AgilePlannerDT.Persister.Impl.File;
using AgilePlannerDT.Persister.Impl.Socket;
using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using SurfaceApplication.Providers;
using TouchToolkit.Framework;
using TouchToolkit.Framework.TouchInputProviders;
using TouchToolkit.GestureProcessor.Feedbacks.TouchFeedbacks;
using Line = System.Windows.Shapes.Line;
using Microsoft.Surface.Simulator.Automation;

namespace AgilePlannerDT.Window
{
    /// <summary>
    /// Interaction logic for AgilePlannerMicrosoftSurfaceWindow.xaml
    /// </summary>
    public partial class AgilePlannerMicrosoftSurfaceWindow : SurfaceWindow, AgilePlannerApplication
    {

        private bool _sendMouseMoveInfo = false;
        private SurfaceTouchInputProvider touchProvider;
        private int firstTouchId;
        private Color defaultColor = CardConstants.YELLOW;
        private DisplayObject activeCard, selectedCard;
        private bool isLoadingPhase = false;
        private bool areCardsHighlighted = false;
        private List<ApCommand> commands = new List<ApCommand>();
        private Dictionary<Dictionary<int, int>, MousePointer> mouses = new Dictionary<Dictionary<int, int>, MousePointer>();
        private Dictionary<long, DisplayObject> cards = new Dictionary<long, DisplayObject>();
        private List<Dictionary<int, int>> deletedKey = new List<Dictionary<int, int>>();
        private List<int> currentTouchPointsOnScreen = new List<int>();

        GestureRecognizer gestureRecognizer;
        int[] StrokeToIdMapping;
        Stroke[] GestureStrokes;
        Collection<Line>[] gestureLines;
        Dictionary<int, DisplayObject> touchCardMapping;
        //max number of ink gestures allowed at the same time
        const int MAXGESTURES = 5;

        private Brush _inkStrokeColor = Brushes.Yellow;

        private GestureModule gestureModule;
        private PersisterModule persisterModule;
        private IndexCardEventHandlerModule eventModule;

        private FloatingToolBox ftoolbox;

        private Timer cardsHighlightedTimer;

        private List<int> contactDownIDs = new List<int>();
        private Button sample;

        public AgilePlannerMicrosoftSurfaceWindow()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(AgilePlannerMicrosoftSurfaceWindow_Loaded);
            this.TouchDown += new EventHandler<TouchEventArgs>(AgilePlannerMicrosoftSurfaceWindow_TouchDown);

            touchCardMapping = new Dictionary<int, DisplayObject>();

            StrokeToIdMapping = new int[MAXGESTURES];
            gestureLines = new Collection<Line>[MAXGESTURES];
            GestureStrokes = new Stroke[MAXGESTURES];
            touchCardMapping = new Dictionary<int, DisplayObject>();

            for (int i = 0; i < MAXGESTURES; ++i)
            {
                StrokeToIdMapping[i] = -1;
                gestureLines[i] = new Collection<Line>();
            }
           


            gestureRecognizer = new GestureRecognizer();

            gestureRecognizer.SetEnabledGestures(new[] {ApplicationGesture.AllGestures,});
     
            gestureModule = new GestureModuleImpl(this, this.Dispatcher, this.gestureRecognizer);


            eventModule = new IndexCardEventHandlerModuleImpl(this, this.Dispatcher, this.windowCanvas, this.gestureModule);

            cardsHighlightedTimer = new System.Timers.Timer(2000);
            cardsHighlightedTimer.Elapsed += new ElapsedEventHandler(cardsHighlightedTimer_Elapsed);

            ftoolbox = new FloatingToolBox(this);
            ftoolbox.IsManipulationEnabled = true;
            ftoolbox.TouchDown += new EventHandler<TouchEventArgs>(ftoolbox_TouchDown);
          
            ftoolbox.OnWebServiceURLChanged += FloatingToolbox_OnWebServiceURLChanged;
            ftoolbox.OnDisconnectButtonClicked += FloatindToolbox_OnDisconnectButtonClicked;

            ftoolbox.exitButton.TouchDown += new EventHandler<TouchEventArgs>(exitButton_TouchDown);
            windowCanvas.Children.Add(ftoolbox);
            
        }

        public Canvas getCanvas()
        {
            return this.windowCanvas;
        }

        void ftoolbox_TouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void exitButton_TouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void ButtonTap(UIElement sender, GestureEventArgs e)
        {
            
        }

        private void ToolBoxExitTap(UIElement sender, GestureEventArgs e)
        {
         
        }

        void AgilePlannerMicrosoftSurfaceWindow_Loaded(object sender, RoutedEventArgs e)
        {
            touchProvider = new SurfaceTouchInputProvider(this);
            
            GestureFramework.Initialize(touchProvider, LayoutRoot);
            //show bubbles trail for touch feedback
            //GestureFramework.AddTouchFeedback(typeof(BubblesPath));
            //GestureFramework.EventManager.AddEvent(TestButton, "Tap", TestButton_TouchDown);
            //GestureFramework.EventManager.AddEvent(surfacebutton, "Tap", surfacebutton_TouchDown);

            //this.IsManipulationEnabled = true;
            //sample = new SurfaceButton
            //             {
            //                 Width = 100,
            //                 Height = 50,
            //                 Background = new SolidColorBrush(Colors.Red),
            //                 Content = "CLICK ME"
            //             };
            //sample.SetValue(Canvas.LeftProperty, 500.0);
            //sample.SetValue(Canvas.TopProperty, 400.0);
            ////sample.Click += new RoutedEventHandler(sample_Click);
            ////sample.PreviewTouchDown += new EventHandler<TouchEventArgs>(sample_PreviewTouchDown);
            //sample.TouchDown += new EventHandler<TouchEventArgs>(sample_TouchDown);
            //sample.TouchUp += new EventHandler<TouchEventArgs>(sample_TouchUp);


            //LayoutRoot.Children.Add(sample);

            //ftoolbox.exitButton.RaiseEvent(new RoutedEventArgs(Button.TouchUpEvent));
            //ftoolbox.IsManipulationEnabled = true;
            //ftoolbox.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(ftoolbox_ManipulationDelta);
            //ftoolbox.exitButton.PreviewTouchDown += new EventHandler<TouchEventArgs>(exitButton_PreviewTouchDown);
            //ftoolbox.PreviewTouchDown += new EventHandler<TouchEventArgs>(ftoolbox_PreviewTouchDown);
            //SurfaceButton temp = new SurfaceButton();
            //temp.Height = ftoolbox.Height;
            //temp.Width = ftoolbox.Width;
            
            //temp.Background = ftoolbox.Background;

            //ftoolbox.exitButton = temp;
            //ftoolbox.exitButton.Click += new RoutedEventHandler(exitButton_Click);
            touchProvider.SingleTouchChanged += ProviderSingleTouchChanged;

        }

        private void surfacebutton_TouchDown(UIElement sender, GestureEventArgs e)
        {
            MessageBox.Show("HIT");
        }
        private void TestButton_TouchDown(UIElement sender, GestureEventArgs e)
        {
            MessageBox.Show("Hit");
        }

        void exitButton_Click(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        void ftoolbox_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            throw new NotImplementedException();
        }

        void sample_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void sample_Click(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        void ftoolbox_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void exitButton_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void AgilePlannerMicrosoftSurfaceWindow_TouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void sample_TouchUp(object sender, TouchEventArgs e)
        {
            e.Handled = true;
            throw new NotImplementedException();
        }

        void sample_TouchDown(object sender, TouchEventArgs e)
        {
            e.Handled = true;
            throw new NotImplementedException();
        }


        void ProviderSingleTouchChanged(object sender, SingleTouchEventArgs e)
        {
            var touchId = e.TouchPoint.TouchDeviceId;

            switch (e.TouchPoint.Action)
            {
                case TouchAction.Down:
                    if (!contactDownIDs.Contains(touchId))
                    {
                        contactDownIDs.Add(touchId);
                        TouchContactDown(e.TouchPoint.Position, e.TouchPoint.TouchDeviceId);
                    }
                    return;
                case TouchAction.Move:
                    TouchContactMove(e.TouchPoint.Position, e.TouchPoint.TouchDeviceId);
                    return;
                case TouchAction.Up:
                    if (contactDownIDs.Contains(touchId))
                    {
                        contactDownIDs.Remove(touchId);
                        TouchContactUp(e.TouchPoint.Position, e.TouchPoint.TouchDeviceId);
                    }
                    return;
            } 
        }

        #region Touch Event Handlers

        void TouchContactDown(Point touchPoint, int touchId)
        {
            if (currentTouchPointsOnScreen.Count == 0)
            {
                firstTouchId = touchId;
                //Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point((int)(touchPoint.X - 1024), (int)(touchPoint.Y));
                //Core.InputDevices.Mouse.LeftDown();
            }

            currentTouchPointsOnScreen.Add(touchId);

            var activatedCard = (DisplayObject)Dispatcher.Invoke(DispatcherPriority.Render, new AgilePlannerMainWindow.getPosition(GetCurrentArtefact), (touchPoint));            

            if (activatedCard != null)
            {
                //disable the second touch on the same artefact
                if (touchCardMapping.ContainsValue(activatedCard))
                {
                    return;
                }

                if (!touchCardMapping.ContainsKey(touchId))
                {
                    touchCardMapping.Add(touchId, activatedCard);
                }
                else
                {
                    touchCardMapping[touchId] = activatedCard;
                }

                
                Dispatcher.Invoke(DispatcherPriority.Render, new AgilePlannerMainWindow.OnTouchEvent(activatedCard.OnTouchDown), touchPoint);

                //do not continue the gesture recognition);
                return;
            }

            //inking on canvas for gesture recognition
            var currentMapping = -1;

            for (int i = 0; i < MAXGESTURES; ++i)
            {
                if (StrokeToIdMapping[i] == -1)
                {
                    StrokeToIdMapping[i] = touchId;
                    currentMapping = i;
                    break;
                }
            }
            if (-1 != currentMapping)
            {
                GestureStrokes[currentMapping] = (Stroke)Dispatcher.Invoke(DispatcherPriority.Render, new AgilePlannerMainWindow.CreateStroke(InitializeInkStroke), touchPoint);
            }

        }

        void TouchContactMove(Point touchPoint, int touchId)
        {
            if (touchId==firstTouchId)
            {
                //Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point((int) (touchPoint.X - 1024),
                 //                                                                    (int) (touchPoint.Y));
            }
            if (touchCardMapping.ContainsKey(touchId) && touchCardMapping[touchId] != null)
            {
                var activatedCard = touchCardMapping[touchId];

                Dispatcher.Invoke(DispatcherPriority.Render, new AgilePlannerMainWindow.OnTouchEvent(activatedCard.OnTouchMove), touchPoint);

                return;
            }

            int currentMapping = FindMappingIndex(touchId);

            if (-1 != currentMapping)
            {
                var start = GestureStrokes[currentMapping].StylusPoints[GestureStrokes[currentMapping].StylusPoints.Count - 1];
                GestureStrokes[currentMapping].StylusPoints.Add(new StylusPoint(touchPoint.X, touchPoint.Y));
                Dispatcher.Invoke(DispatcherPriority.Render, new AgilePlannerMainWindow.drawStroke(DrawInkStroke), new Point(start.X, start.Y), touchPoint, this.gestureLines[currentMapping]);
            }    
            
        }

        void TouchContactUp(Point touchPoint, int touchId)
        {
            if (firstTouchId == touchId)
            {
                //Core.InputDevices.Mouse.LeftUp();
            }

            currentTouchPointsOnScreen.Remove(touchId);

            //if (TouchUpOnButton(touchPoint))
            //{
            //    return;
            //}

            if (touchCardMapping.ContainsKey(touchId) && touchCardMapping[touchId] != null)
            {
                var activatedCard = touchCardMapping[touchId];
                touchCardMapping.Remove(touchId);

                Dispatcher.Invoke(DispatcherPriority.Render, new AgilePlannerMainWindow.OnTouchEvent(activatedCard.OnTouchUp), touchPoint);

                return;
            }

            

            int currentMapping = FindMappingIndex(touchId);

            if (-1 != currentMapping)
            {
                StrokeToIdMapping[currentMapping] = -1;
                GestureStrokes[currentMapping].StylusPoints.Add(new StylusPoint(touchPoint.X, touchPoint.Y));

                var sc = new StrokeCollection {GestureStrokes[currentMapping]};
                var results =
                    (ReadOnlyCollection<GestureRecognitionResult>)
                    Dispatcher.Invoke(DispatcherPriority.Render,
                                           new AgilePlannerMainWindow.RecognizeText(gestureRecognizer.Recognize), sc);
                if (results.Count > 0)
                {
                    Dispatcher.Invoke(DispatcherPriority.Render,
                                           new AgilePlannerMainWindow.processGesture(gestureModule.ProcessGesture), this,
                                           new InkCanvasGestureEventArgs(sc, results));

                    Console.WriteLine(results[0].ApplicationGesture);

                }
                Dispatcher.Invoke(DispatcherPriority.Render,
                                       new AgilePlannerMainWindow.removeStroke(RemoveInkStroke), this.gestureLines[currentMapping]);
            }
        }

        #endregion

        #region Hit test methods

        private  List<DependencyObject> buttonHitTestResults = new List<DependencyObject>();

        private bool TouchUpOnButton(Point point)
        {
            var result = VisualTreeHelper.HitTest(this.windowCanvas, point);

            if (result == null)
                return false;

            var visualComponent = result.VisualHit;
            if (visualComponent is DrawingVisual)
                visualComponent = VisualTreeHelper.GetParent(visualComponent);

            var result2 = visualComponent as FrameworkElement;
            var ass = result2.TemplatedParent.DependencyObjectType;
            if (result2 != null && result2.TemplatedParent != null && result2.TemplatedParent.GetType() == typeof (Button))
            {
                ((Button) result2.TemplatedParent).RaiseEvent(new RoutedEventArgs((Button.ClickEvent)));
                return true;
            } 
            else if (result2.TemplatedParent != null && result2.TemplatedParent.GetType() == typeof (ComboBox))
            {
                //((ComboBox)result2.TemplatedParent).RaiseEvent(new RoutedEventArgs((ComboBox.MouseLeftButtonDownEvent)));
                return true;
            }

            return false;
        }

        private DisplayObject GetCurrentArtefact(Point point)
        {
            //buttonHitTestResults.Clear();

            //VisualTreeHelper.HitTest(this, new HitTestFilterCallback(ButtonHitTestFilterCallback), new HitTestResultCallback(ButtonHitTestResult),
            //                         new PointHitTestParameters(point));
            
            var result = VisualTreeHelper.HitTest(this.windowCanvas, point);

            //if(buttonHitTestResults.Count != 0)
            //{
            //    foreach(var dep_obj in buttonHitTestResults)
            //    {
            //        var stuff = dep_obj.GetType();
            //        if(stuff == typeof(Button))
            //        {
                        
            //        }
            //    }
            //}
            //var sas = VisualTreeHelper.GetParent(result.VisualHit);

            if (result == null)
                return null;

            var visualComponent = result.VisualHit;
            if (visualComponent is DrawingVisual)
                visualComponent = VisualTreeHelper.GetParent(visualComponent);

            var result2 = visualComponent as FrameworkElement;
            while (result2 != null && result2 != this)
            {

                if (result2 is DisplayObject)
                {
                    return (DisplayObject)result2;

                }

                if (((FrameworkElement)result2).DataContext != null && ((FrameworkElement)result2).DataContext is DisplayObject)
                    return (DisplayObject)(((FrameworkElement)result2).DataContext);
                if (LogicalTreeHelper.GetParent(result2) == null || LogicalTreeHelper.GetParent(result2).Equals(result2))
                {
                    return null;
                }

                result2 = result2.Parent as FrameworkElement;
            }
            return null;
        }

        private HitTestFilterBehavior ButtonHitTestFilterCallback(DependencyObject target)
        {
            if(target.GetType().IsAssignableFrom(typeof(Button)))
            {
                buttonHitTestResults.Add(target);
                return HitTestFilterBehavior.Stop;
            }
            else
            {
                return HitTestFilterBehavior.Continue;
            }
        }
        private HitTestResultBehavior ButtonHitTestResult(HitTestResult result)
        {
            //var temp = result.VisualHit as FrameworkElement;
            //buttonHitTestResults.Add(result);
            return HitTestResultBehavior.Stop;
        }


        #endregion

        #region Ink canvas drawing handling methods

        private Stroke InitializeInkStroke(Point p)
        {

            return new Stroke(new StylusPointCollection(new Point[] { p }));

        }

        private void DrawInkStroke(Point start, Point end, Collection<Line> lineCollection)
        {
            Line connectingLine = new Line();
            connectingLine.Stroke = _inkStrokeColor;
            connectingLine.StrokeThickness = 3;
            connectingLine.X1 = start.X;
            connectingLine.X2 = end.X;
            connectingLine.Y1 = start.Y;
            connectingLine.Y2 = end.Y;
            this.windowCanvas.Children.Add(connectingLine);
            lineCollection.Add(connectingLine);
        }

        private void RemoveInkStroke(Collection<Line> deletedLines)
        {
            foreach (var line in deletedLines)
            {
                windowCanvas.Children.Remove(line);
            }
            deletedLines.Clear();
        }

        private int FindMappingIndex(int ID)
        {
            for (int i = 0; i < MAXGESTURES; ++i)
            {
                if (StrokeToIdMapping[i] == ID)
                {
                    return i;
                }
            }
            return -1;
        }

        #endregion

        private delegate void HighlightDelegate();

        private void cardsHighlightedTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            cardsHighlightedTimer.Stop();

            this.Dispatcher.Invoke(DispatcherPriority.Render, new HighlightDelegate(Highlight));
        }

        private void FloatindToolbox_OnDisconnectButtonClicked()
        {
            if (Persister != null)
            {
                if (Persister is AsyncXMLSocketPersister)
                    ((AsyncXMLSocketPersister)Persister).stop();//close the inbound and outbound thread
                Persister.RemovePlannerDataChangeListener(persisterModule);
            }
        }

        private void FloatingToolbox_OnWebServiceURLChanged(string uri)
        {
            if (Persister != null)
            {
                if (Persister is AsyncXMLSocketPersister)
                    ((AsyncXMLSocketPersister)Persister).stop();//close the inbound and outbound thread
                Persister.RemovePlannerDataChangeListener(persisterModule);
            }

            if (uri.Equals("localhost"))
            {
                persisterModule = new PersisterModuleImpl(this, this.Dispatcher,
                    new AsyncWrapperPersister(new SyncPersisterToXML()));
            }
            else
            {
                int port = 5555;
                string url = "";
                try
                {
                    url = analyzeURI(uri, out port);
                }
                catch
                {
                    throw new FormatException();

                }
                try
                {
                    persisterModule = new PersisterModuleImpl(this, this.Dispatcher,
                        new AsyncXMLSocketPersister(new SocketConnection(url, port), this.Dispatcher));
                }
                catch (SocketException e)
                {
                    throw e;
                }

                //     Properties.Settings.Default.LastHost = uri;
            }

            Persister.AddPlannerDataChangeListener(persisterModule);
            ftoolbox.Persister = Persister;
        }

        /// <summary>
        /// Return IP and port number from a vaild
        /// URI
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        private string analyzeURI(string uri, out int port)
        {
            Regex r = new Regex(":");
            string[] target = r.Split(uri);
            if (target.Length == 1)
            {
                port = 5555;
                return target[0];
            }
            else
            {
                try
                {
                    port = Int32.Parse(target[1]);
                    return target[0];
                }
                catch
                {
                    throw new FormatException();
                }
            }
        }

        public bool SendMouseMoveInfoEnabled
        {
            get { return this._sendMouseMoveInfo; }
            set { this._sendMouseMoveInfo = value; }
        }

        public DisplayObject ActiveCard
        {
            get { return this.activeCard; }
            set { this.activeCard = value; }
        }

        public Dictionary<long, DisplayObject> Cards
        {
            get { return this.cards; }
            set { this.cards = value; }
        }

        public List<ApCommand> Commands
        {
            get { return this.commands; }
        }

        public Color DefaultColor
        {
            get { return defaultColor; }
            set
            {
                defaultColor = value;

                if ((SelectedCard != null) && (SelectedCard is StoryCardDisplayObject))
                {
                    ((StoryCardDisplayObject)SelectedCard).CardColor = value;
                }
            }
        }

        public bool IsLoadingPhase
        {
            get { return isLoadingPhase; }
            set { isLoadingPhase = value; }
        }

        public AsynchronousPersister Persister
        {
            get
            {
                if (persisterModule != null)
                    return this.persisterModule.Persister;
                else
                    return null;
            }
            set { this.persisterModule.Persister = value; }
        }

        public Project Project
        {
            get
            {
                if (persisterModule != null)
                    return persisterModule.Project;
                else
                    return null;
            }
            set { persisterModule.Project = value; }
        }

        public DisplayObject SelectedCard
        {
            get { return this.selectedCard; }
            set
            {
                if (this.selectedCard != null)
                    this.selectedCard.Select();

                this.selectedCard = value;

                if (this.selectedCard != null)
                    this.selectedCard.Select();
            }
        }

        public DisplayObject ToolBox
        {
            get { return this.ftoolbox; }
        }

        public bool IsVotingEnabled
        {
            get; set;
        }

        public void AddCommand(ApCommand command)
        {
            //throw new NotImplementedException();
        }

        public void BringToFront(DisplayObject sender)
        {
            if (sender is StoryCardDisplayObject)
            {
                StoryCardDisplayObject storycard = (StoryCardDisplayObject)sender;

                DisplayObject dobj;
                if (cards.TryGetValue(storycard.ParentID, out dobj))
                {

                    if (dobj is IterationDisplayObject)
                    {
                        IterationDisplayObject iteration = (IterationDisplayObject)dobj;

                        //assures that the storycards will reappear in the right order
                        //on reload
                        iteration.RemoveStoryCard(storycard);
                        iteration.AddStoryCard(storycard);
                    }
                }

                windowCanvas.Children.Remove((UIElement)sender);
                windowCanvas.Children.Add((UIElement)sender);
            }
            else if (sender is IterationDisplayObject)
            {
                IterationDisplayObject iteration = (IterationDisplayObject)sender;

                foreach (StoryCardDisplayObject sc in iteration.StoryCardChildren)
                {
                    windowCanvas.Children.Remove((UIElement)sc);
                }

                windowCanvas.Children.Remove((UIElement)sender);
                windowCanvas.Children.Add((UIElement)sender);

                foreach (StoryCardDisplayObject sc in iteration.StoryCardChildren)
                {
                    windowCanvas.Children.Add((UIElement)sc);
                }

            }
            else
            {
                windowCanvas.Children.Remove((UIElement)sender);
                windowCanvas.Children.Add((UIElement)sender);
            }

            //the floating toolbox is always on top of everything
            windowCanvas.Children.Remove(ftoolbox);
            windowCanvas.Children.Add(ftoolbox);
        }

        public void Clear()
        {
            windowCanvas.Children.Clear();
            cards.Clear();
            windowCanvas.Children.Add(ftoolbox);
        }

        private void DisplayObject_OnFadeOutCompleted(DisplayObject sender)
        {
            DisplayObject parent;

            if (sender is StoryCardDisplayObject)
            {
                if (cards.TryGetValue(sender.ParentID, out parent))
                {
                    if (parent is IterationDisplayObject)
                    {
                        ((IterationDisplayObject)parent).RemoveStoryCard((StoryCardDisplayObject)sender);
                    }
                }
            }

            windowCanvas.Children.Remove((UIElement)sender);

            SelectedCard = Next();
        }

        public IterationDisplayObject CreateIteration(Iteration iteration)
        {
            if (iteration.Name == "Default StateArea")
            {
                StateAreaDisplayObjectImpl iter = new StateAreaDisplayObjectImpl(iteration, this);

                //register event listeners
                iter.PreviewMouseLeftButtonDown +=
                    new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonDownHandler);
                iter.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonUpHandler);
                iter.PreviewMouseMove += new MouseEventHandler(eventModule.PreviewMouseMoveHandler);
                iter.IterationData.PropertyChanged += new PropertyChangedEventHandler(eventModule.PropertyChangedHandler);
                iter.OnIndexCardDropped +=
                    new DisplayObjectImpl.IndexCardDroppedEventHandler(eventModule.IndexCardDropHandler);
                iter.OnFadeOutCompleted +=
                    new DisplayObjectImpl.FadeOutCompletedEventHandler(DisplayObject_OnFadeOutCompleted);

                //add the iteration to the lookup and the canvas
                cards.Add(iter.ID, iter);
                windowCanvas.Children.Add(iter);

                SelectedCard = iter;

                return iter;
            }
            else
            {
                IterationDisplayObjectImpl iter = new IterationDisplayObjectImpl(iteration, this);

                //register event listener
                iter.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonDownHandler);
                iter.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonUpHandler);
                iter.PreviewMouseMove += new MouseEventHandler(eventModule.PreviewMouseMoveHandler);
                iter.IterationData.PropertyChanged += new PropertyChangedEventHandler(eventModule.PropertyChangedHandler);
                iter.OnIndexCardDropped += new DisplayObjectImpl.IndexCardDroppedEventHandler(eventModule.IndexCardDropHandler);
                iter.OnFadeOutCompleted += new DisplayObjectImpl.FadeOutCompletedEventHandler(DisplayObject_OnFadeOutCompleted);

                //add the iteration to the lookup and the canvas
                cards.Add(iter.ID, iter);
                windowCanvas.Children.Add(iter);

                //resize it
                /*         double startupWidth = iteration.Width - CardConstants.ITERATION_DEFAULT_WIDTH;
                         double startupHeight = iteration.Height - CardConstants.ITERATION_DEFAULT_HEIGHT;

                         iter.Resize(startupWidth > 0 ? startupWidth : 0,
                             startupHeight > 0 ? startupHeight : 0);
                         */
                SelectedCard = iter;

                return iter;
            }
        }

        public StoryCardDisplayObject CreateStoryCard(StoryCard storycard)
        {
            StoryCardDisplayObjectImpl sc = new StoryCardDisplayObjectImpl(storycard, this, storycard.Background);
            sc.Opacity = 1;
            //register event listeners
            sc.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonDownHandler);
            sc.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonUpHandler);
            sc.PreviewMouseMove += new MouseEventHandler(eventModule.PreviewMouseMoveHandler);
            sc.OnIndexCardDropped += new DisplayObjectImpl.IndexCardDroppedEventHandler(eventModule.IndexCardDropHandler);
            sc.StoryCardData.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(eventModule.PropertyChangedHandler);
            sc.OnFadeOutCompleted += new DisplayObjectImpl.FadeOutCompletedEventHandler(DisplayObject_OnFadeOutCompleted);

            //add sc to lookup and canvas
            cards.Add(sc.ID, sc);
            windowCanvas.Children.Add(sc);
            /*
                        //resize it
                        double startupWidth = storycard.Width - CardConstants.STORYCARD_DEFAULT_WIDTH;
                        double startupHeight = storycard.Height - CardConstants.STORYCARD_DEFAULT_HEIGHT;

                        sc.Resize(startupWidth > 0 ? startupWidth : 0,
                            startupHeight > 0 ? startupHeight : 0);
                        */
            //       if this card is a TextArea
            if (storycard.Background.Equals(CardConstants.TRANSPARENT))
            {
                sc.switchStoryCardToTextArea();
            }
            SelectedCard = sc;

            return sc;
        }

        public void CreateRemoteMouse(MouseMove move)
        {
            MousePointer mouse = new MousePointer(move, this);
            Dictionary<int, int> keys = new Dictionary<int, int>();
            keys.Add(move.ClientID, move.TouchID);
            mouses.Add(keys, mouse);
            windowCanvas.Children.Add(mouse);
            mouse.FadeIn();
        }

        public void UpdateRemoteMouse(MouseMove move)
        {
            MousePointer pointer = null;
            //  Dictionary<int, int> keys = new Dictionary<int, int>();
            //  keys.Add(move.ClientID, move.TouchID);
            foreach (Dictionary<int, int> keys in mouses.Keys)
            {
                if (keys.ContainsValue(move.TouchID) && keys.ContainsKey(move.ClientID))
                    mouses[keys].Update(move);

            }
        }

        public bool isRemoteMouseExisted(MouseMove move)
        {
            foreach (Dictionary<int, int> keys in mouses.Keys)
            {
                if (keys.ContainsKey(move.ClientID) && keys.ContainsValue(move.TouchID))
                    return true;
            }
            return false;
        }

        public void DeleteRemoteMouse(int client)
        {
            MousePointer pointer = null;

            foreach (Dictionary<int, int> keys in mouses.Keys)
            {
                if (keys.ContainsKey(client) && mouses.TryGetValue(keys, out pointer))
                {
                    //    mouses.Remove(client);
                    //   mouses.Remove(keys);
                    deletedKey.Add(keys);
                    //          mouses.
                    windowCanvas.Children.Remove(pointer);

                }
            }

            foreach (Dictionary<int, int> shouldBeDeleted in deletedKey)
            {
                mouses.Remove(shouldBeDeleted);
            }
            deletedKey.Clear();
        }

        public DisplayObject Delete()
        {
            return Delete(SelectedCard);
        }

        public DisplayObject Delete(DisplayObject card)
        {
            if (card is IterationDisplayObject)
            {
                commands.Add(new IterationDeleteCommand(this, (Iteration)((IterationDisplayObject)card).IterationData.Clone()));
                //                card.g
                Persister.DeleteIteration(card.ID);
            }
            else if (card is StoryCardDisplayObject)
            {
                commands.Add(new StoryCardDeleteCommand(this, (StoryCard)((StoryCardDisplayObject)card).StoryCardData.Clone()));
                Persister.DeleteStoryCard(card.ID);
            }

            return card;
        }

        public double GetHeight()
        {
            return Math.Max(ActualHeight, Height);
        }

        public double GetWidth()
        {
            return Math.Max(ActualWidth, Width);
        }

        public void Highlight()
        {
            foreach (DisplayObject card in cards.Values)
            {
                card.Highlight();
            }

            if (!areCardsHighlighted)
            {
                cardsHighlightedTimer.Start();
                areCardsHighlighted = true;
            }
            else
            {
                areCardsHighlighted = false;
            }
        }

        public DisplayObject Next()
        {
            if (SelectedCard != null)
            {
                long currentID = SelectedCard.ID;
                if (cards.Count == 0)
                    return null;
                else
                {
                    do
                    {
                        if (cards.GetEnumerator().Current.Key != currentID)
                            return cards.GetEnumerator().Current.Value;
                    } while (cards.GetEnumerator().MoveNext());

                }
            }
            return null;
        }

        public DisplayObject Previous()
        {
            if (SelectedCard != null)
            {
                long currentID = selectedCard.ID;

                //try to find a lower id
                for (long i = currentID - 1; i > 0; i--)
                {
                    if (cards.ContainsKey(i))
                    {
                        DisplayObject card;
                        if (cards.TryGetValue(i, out card))
                        {
                            SelectedCard = card;
                            return SelectedCard;
                        }
                    }
                }

                //if none found try to find a higher one
                for (long i = 1000; i > currentID - 1; i--)
                {
                    if (cards.ContainsKey(i))
                    {
                        DisplayObject card;
                        if (cards.TryGetValue(i, out card))
                        {
                            SelectedCard = card;
                            return SelectedCard;
                        }
                    }
                }
            }
            return null;
        }

        public bool TryFindIteration(Point p, out IterationDisplayObject value)
        {
            foreach (DisplayObject card in cards.Values)
            {
                if (card is IterationDisplayObject)
                {
                    if (card.Contains(p))
                    {
                        value = (IterationDisplayObject)card;
                        return true;
                    }
                }
            }

            value = null;
            return false;
        }

        public void ClearVoteDots()
        {
            foreach (KeyValuePair<long, DisplayObject> card in cards)
            {
                if (card.Value is StoryCardDisplayObject)
                {
                    ((StoryCardDisplayObject)card.Value).ClearVoteDots();
                }
            }
        }

        public void SynchronizeResizingCard(DisplayObject card, Point p, int touchID)
        {

        }

        public void SynchornizeMovingCard(DisplayObject card, Point p, int touchID)
        {
        }
        public void HandleMouseMoveLoadedEvent(MouseMove move)
        {
            if (move.ThirdPartyObject is CardPoistionSynchronization)
            {
                CardPoistionSynchronization currentPosition = (CardPoistionSynchronization)(move.ThirdPartyObject);
                DisplayObject target = null;
                if (this.cards.TryGetValue((long)currentPosition.CardID, out target))
                {
                    if (target is StoryCardDisplayObject)
                    {
                        Console.WriteLine("orginialAngle:" + target.RotationAngle + "  " + "targetAngle: " + currentPosition.RotationAngle);
                        ((StoryCardDisplayObject)target).Move((currentPosition.X * Properties.Settings.Default.Scale - target.LocationX), (currentPosition.Y * Properties.Settings.Default.Scale - target.LocationY), (currentPosition.RotationAngle - target.RotationAngle));
                        //     ((StoryCardDisplayObject)target).Move((currentPosition.X - target.LocationX) , (currentPosition.Y - target.LocationY) , (currentPosition.RotationAngle - target.RotationAngle) );
                    }
                    if (target is IterationDisplayObject)
                    {
                        ((IterationDisplayObject)target).Move((currentPosition.X * Properties.Settings.Default.Scale - target.LocationX), (currentPosition.Y * Properties.Settings.Default.Scale - target.LocationY), (currentPosition.RotationAngle - target.RotationAngle));
                    }
                }

            }
            if (move.ThirdPartyObject is CardSizeSynchronization)
            {
                CardSizeSynchronization currentSize = (CardSizeSynchronization)(move.ThirdPartyObject);
                DisplayObject target = null;
                if (this.cards.TryGetValue((long)currentSize.CardID, out target))
                {
                    double dx = currentSize.Width - target.Width;
                    double dy = currentSize.Height - target.Height;
                    target.Resize(ref dx, ref dy);
                    ((DisplayObjectImpl)target).refitCardCenterAndAbsolutePosition(dx, dy);

                }
            }
        }


       
    }
}
